import os
import shutil
import zipfile

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QTabWidget, QMessageBox, QScrollArea, \
    QDialogButtonBox, QTextEdit, QDialog, QLabel, QFileDialog

from LanguageTool import getCNfromDict
from LisenceTool import getActStatus
from SpiFlashUpdateModelTool import addSpiFlashUpdateModelDict, getSpiFlashUpdateModelDict, getFlashUpdateModelVersion, \
    setFlashUpdateModelVersion, saveFlashUpdateModel, delSpiFlashUpdateModelDict
from SpiFlashUpdateWidget import SpiFlashUpdateWidget
from fileOpTool import generate_unique_folder_name, UnzipThread, ensure_folder_exists, get_all_folder_names, \
    delete_folder, ZipThread_spiFlashUpdate, ModifyThread_spiFlashUpdate
from mylog import addLog
from progressWindow import ProgressDialog
from reTool import is_valid_windows_filename


class MultiLineInputDialog(QDialog):
    def __init__(self, parent=None, projectName="", version=""):
        super().__init__(parent)

        self.setWindowTitle(getCNfromDict('TabBar02-projectsetting'))
        # 设置窗口标志，移除关闭按钮和问号按钮
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.setFixedSize(400, 150)
        # 创建文本编辑器
        self.projectName_label = QLabel(getCNfromDict('TabBar02-projectsettingName'), self)
        self.projectName_edit = QTextEdit(self)
        self.projectVersion_label = QLabel(getCNfromDict('TabBar02-projectsettingVersion'), self)
        self.projectVersion_edit = QTextEdit(self)

        self.projectName_edit.setText(projectName)
        self.projectVersion_edit.setText(version)

        # 创建按钮盒
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        hlayout1 = QHBoxLayout()
        hlayout1.addWidget(self.projectName_label)
        hlayout1.addWidget(self.projectName_edit)

        hlayout2 = QHBoxLayout()
        hlayout2.addWidget(self.projectVersion_label)
        hlayout2.addWidget(self.projectVersion_edit)

        # 布局
        layout = QVBoxLayout()
        layout.addLayout(hlayout1)
        layout.addLayout(hlayout2)
        layout.addWidget(self.button_box)
        self.setLayout(layout)

    def get_text(self):
        return [self.projectName_edit.toPlainText(), self.projectVersion_edit.toPlainText()]


class TabBar02(QWidget):
    def __init__(self):
        super().__init__()

        # 创建垂直布局作为主布局
        main_layout = QVBoxLayout()

        # ===== 第一部分：按钮行 =====
        # 创建一个水平布局，用于存放按钮
        button_layout = QHBoxLayout()

        # 创建按钮
        self.btn_new = QPushButton(getCNfromDict('TabBar02-btnnewtxt'))
        self.btn_import = QPushButton(getCNfromDict('TabBar02-btnimporttxt'))
        self.btn_close = QPushButton(getCNfromDict('TabBar02-btnclosetxt'))
        self.btn_del = QPushButton(getCNfromDict('TabBar02-btndeltxt'))
        self.btn_modify = QPushButton(getCNfromDict('TabBar02-btnmodifytxt'))
        self.btn_generate = QPushButton(getCNfromDict('TabBar02-btngeneratetxt'))

        if getActStatus():
            self.btn_modify.setEnabled(True)
            self.btn_generate.setEnabled(True)
        else:
            self.btn_modify.setEnabled(False)
            self.btn_generate.setEnabled(False)

        self.btn_new.clicked.connect(self.btn_new_clicked)
        self.btn_import.clicked.connect(self.btn_import_clicked)
        self.btn_close.clicked.connect(self.btn_close_clicked)
        self.btn_del.clicked.connect(self.btn_del_clicked)
        self.btn_modify.clicked.connect(self.btn_modify_clicked)
        self.btn_generate.clicked.connect(self.btn_generate_clicked)

        # 将按钮添加到水平布局中
        button_layout.addWidget(self.btn_new)
        button_layout.addWidget(self.btn_import)
        button_layout.addWidget(self.btn_close)
        button_layout.addWidget(self.btn_del)
        button_layout.addWidget(self.btn_modify)
        button_layout.addWidget(self.btn_generate)

        # 将水平布局靠左对齐
        button_layout.addStretch()  # 让按钮靠左，其余部分扩展以填充空间

        # 将水平布局添加到主布局中，并设置固定高度
        main_layout.addLayout(button_layout)
        button_row_height = 50  # 固定高度为 50
        button_layout.setContentsMargins(0, 0, 0, 0)  # 去掉上下左右的空白边距

        # ===== 第二部分：QTabWidget =====
        # 创建 QTabWidget 控件
        self.tab_widget = QTabWidget()
        self.tab_widget.tabBarDoubleClicked.connect(self.onTabBarDoubleClicked)
        self.scanProject()

        # 将 QTabWidget 添加到主布局
        main_layout.addWidget(self.tab_widget)

        # 设置主窗口的布局
        self.setLayout(main_layout)

        # 解压线程
        self.unzip_thread = None
        # 各种进度弹窗
        self.progress_dialog = None
        # 压缩线程
        self.zip_thread = None
        # 修改线程
        self.modify_thread = None
        # 正在处理的工程名
        self.tmpProjectName = ""

    def onTabBarDoubleClicked(self, index):
        addLog('TabBar02', 'info', f"onTabBarDoubleClicked")
        if index != -1:
            # print(index)
            # 创建输入对话框以修改标签名称
            self.tmpProjectName = self.tab_widget.tabText(index)
            # 获取原来版本信息
            orgVersion = getFlashUpdateModelVersion(self.tmpProjectName)
            addLog('TabBar02', 'info', f"project name: {self.tmpProjectName}; version: {orgVersion}")
            # 弄一个窗口，可以改工程名和版本信息
            dialog = MultiLineInputDialog(self, self.tmpProjectName, orgVersion)

            if dialog.exec_() == QDialog.Accepted:
                settings = dialog.get_text()
                # 判断内容是否有修改，修改是否合法，执行修改
                if settings[1].isdigit():
                    if settings[1] != orgVersion:
                        if int(settings[1]) == 1 or 30 <= int(settings[1]) <= 255:
                            # 执行修改
                            setFlashUpdateModelVersion(self.tmpProjectName, settings[1])
                            saveFlashUpdateModel(self.tmpProjectName)
                            addLog('TabBar02', 'info', f"set version:{settings[1]}, set over!")
                        else:
                            # 请使用大于30的版本号
                            self.show_message(getCNfromDict('TabBar02-projectsettingVerErr'), 1)
                            addLog('TabBar02', 'warn', f"set version:{settings[1]}, not in range[30, 255]")
                            return
                else:
                    # 版本信息请输入数字
                    self.show_message(getCNfromDict('TabBar02-projectsettingVerErr'), 1)
                    addLog('TabBar02', 'warn', f"set version:{settings[1]}, not in range[30, 255]")
                    return

                # 判断工程名是否修改，修改是否合法，执行修改
                if self.tmpProjectName != settings[0]:
                    if is_valid_windows_filename(self.tmpProjectName):
                        # print(index, new_Name)
                        try:
                            # 重命名文件夹
                            os.rename('./project/mcu/' + self.tmpProjectName, './project/mcu/' + settings[0])
                            # 需要同步更新列表中的项目名，比较麻烦，因此直接把项目关了，再重新开
                            # 删除当前页面
                            delSpiFlashUpdateModelDict(self.tmpProjectName)
                            self.tab_widget.removeTab(index)
                            self.addProject(settings[0])
                            # 设置当前选中的 Tab 为新增的 Tab
                            tab_count = self.tab_widget.count() - 1
                            self.tab_widget.setCurrentIndex(tab_count)
                            addLog('TabBar02', 'info', f"set projectname:{settings[0]}, set over!")
                        except FileExistsError:
                            self.show_message(getCNfromDict('TabBar05-btnrenameerr1'), 1)
                            addLog('TabBar02', 'warn', f"projectFile not found!")
                        except Exception as e:
                            self.show_message(getCNfromDict('TabBar05-btnrenameerr2'), 1)
                            addLog('TabBar02', 'error', f"set projectname error!")
                    else:
                        self.show_message(getCNfromDict('TabBar05-btnrenameerr'), 1)
                        addLog('TabBar02', 'error', f"set projectname:{self.tmpProjectName}, is unvalid!")

    def btn_new_clicked(self):
        addLog('TabBar02', 'info', f"btn_new_clicked")
        # 判断原厂压缩包是否存在
        if not os.path.exists('./res/SpiFlashUpdate.zip'):
            # 提示不存在
            self.show_message(getCNfromDict('TabBar02-btnnewerr1'), 1)
            addLog('TabBar02', 'warn', f"./res/SpiFlashUpdate.zip not found!")
        else:
            unique_folder = generate_unique_folder_name('./project/mcu/', 'SpiFlashUpdate')
            os.makedirs(os.path.join('./project/mcu/', unique_folder))
            addLog('TabBar02', 'info', f"folder create：{os.path.join('./project/mcu/', unique_folder)}")
            self.tmpProjectName = unique_folder
            # 创建解压线程
            self.unzip_thread = UnzipThread('./res/SpiFlashUpdate.zip', './project/mcu/' + unique_folder)
            # 创建进度弹窗
            self.progress_dialog = ProgressDialog(getCNfromDict('TabBar02-btnnewing'), self)
            self.progress_dialog.show()

            # 连接信号和槽
            self.unzip_thread.progress_signal.connect(self.progress_dialog.update_progress)
            self.unzip_thread.status_signal.connect(self.btnnew_status)
            self.unzip_thread.status_signal.connect(self.progress_dialog.update_status)

            # 启动线程
            self.unzip_thread.start()
            addLog('TabBar02', 'info', f"start unzip: ./res/SpiFlashUpdate.zip to {'./project/mcu/' + unique_folder}")

    def btnnew_status(self, status):
        """
        更新状态信息。
        """
        if status == 0:
            # 解压完毕
            # 界面导入
            self.addProject(self.tmpProjectName)

            # 设置当前选中的 Tab 为新增的 Tab
            tab_count = self.tab_widget.count() - 1
            self.tab_widget.setCurrentIndex(tab_count)
            addLog('TabBar02', 'info', "unzip or import finish!")
        else:
            self.show_message(getCNfromDict('TabBar02-btnnewerr'), 1)
            addLog('TabBar02', 'info', "unzip or import error!")

    def btn_import_clicked(self):
        addLog('TabBar02', 'info', f"btn_import_clicked")
        # 选择一个zip压缩包
        file_path, _ = QFileDialog.getOpenFileName(self,
                                                   getCNfromDict('TabBar05-btnimportwindow'),
                                                   "",
                                                   "ZIP Files (*.zip)")
        if file_path:
            addLog('TabBar02', 'info', f"Selected file: {file_path}")
            with zipfile.ZipFile(file_path, 'r') as zip_ref:
                # 获取 ZIP 文件中的所有文件名
                file_list = zip_ref.namelist()
                # print(file_list)
                # 判断ZIP目录结构是否有效
                if 'files/SpiFlashInfo.xml' in file_list:
                    # 分割出目录、文件名和扩展名
                    directory, file_name = os.path.split(file_path)
                    file_base, file_ext = os.path.splitext(file_name)
                    projectName = generate_unique_folder_name('./project/mcu', file_base)
                    os.mkdir('./project/mcu/' + projectName)
                    addLog('TabBar02', 'info', f"folder create：{os.path.join('./project/mcu/', projectName)}")
                    self.tmpProjectName = projectName
                    # 创建解压线程
                    self.unzip_thread = UnzipThread(file_path, './project/mcu/' + projectName)
                    # 创建进度弹窗
                    self.progress_dialog = ProgressDialog(getCNfromDict('TabBar05-btnimporting'), self)
                    self.progress_dialog.show()

                    # 连接信号和槽
                    self.unzip_thread.progress_signal.connect(self.progress_dialog.update_progress)
                    self.unzip_thread.status_signal.connect(self.btnnew_status)
                    self.unzip_thread.status_signal.connect(self.progress_dialog.update_status)

                    # 启动线程
                    self.unzip_thread.start()
                    addLog('TabBar02', 'info', f"start unzip: {file_path} to {'./project/mcu/' + projectName}")
                else:
                    self.show_message(getCNfromDict('TabBar05-btnimporterr'), 1)
                    addLog('TabBar02', 'warn', f"{file_path} is unvalid")

    def btn_close_clicked(self):
        addLog('TabBar02', 'info', f"btn_close_clicked")
        # 获取当前标签的数量，没有就无动作
        if self.tab_widget.count():
            # 获取当前标签的名字，删除文件夹，移除标签
            current_index = self.tab_widget.currentIndex()  # 获取当前页面的索引
            if current_index != -1:  # 检查是否有页面
                # 从缓存中清除模型数据
                delSpiFlashUpdateModelDict(self.tab_widget.tabText(current_index))
                # 删除当前页面
                self.tab_widget.removeTab(current_index)
                addLog('TabBar02', 'info', f"close project over")

    def btn_del_clicked(self):
        addLog('TabBar02', 'info', f"btn_del_clicked")
        # 获取当前标签的数量，没有就无动作
        if self.tab_widget.count():
            # 弹出确认对话框
            reply = QMessageBox.question(
                self,
                getCNfromDict('megbox-del'),
                getCNfromDict('megbox-deltxt'),
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No
            )

            # 判断用户选择
            if reply == QMessageBox.Yes:
                # 获取当前标签的名字，删除文件夹，移除标签
                current_index = self.tab_widget.currentIndex()  # 获取当前页面的索引
                if current_index != -1:  # 检查是否有页面
                    # 获取当前页面的标题
                    current_title = self.tab_widget.tabText(current_index)
                    # print(f"即将删除的页面标题: {current_title}")
                    # 删除文件夹
                    delete_folder('./project/mcu/'+current_title)
                    # 从缓存中清除模型数据
                    delSpiFlashUpdateModelDict(current_title)
                    # 删除当前页面
                    self.tab_widget.removeTab(current_index)
                    addLog('TabBar02', 'info', f"delete project over")

    def btn_modify_clicked(self):
        addLog('TabBar02', 'info', f"btn_modify_clicked")
        # 获取当前页面的工程名
        current_index = self.tab_widget.currentIndex()
        if current_index != -1:
            self.tmpProjectName = self.tab_widget.tabText(current_index)
            # 创建修改线程
            self.modify_thread = ModifyThread_spiFlashUpdate(self.tmpProjectName)
            # 创建进度弹窗
            self.progress_dialog = ProgressDialog(getCNfromDict('TabBar05-btnmodifying'), self)
            self.progress_dialog.show()

            # 连接信号和槽
            self.modify_thread.progress_signal.connect(self.progress_dialog.update_progress)
            self.modify_thread.status_signal.connect(self.btnmodify_status)
            self.modify_thread.status_signal.connect(self.progress_dialog.update_status)

            # 启动线程
            self.modify_thread.start()
            addLog('TabBar02', 'info', f"start modify")

    def btnmodify_status(self, status):
        if status == 0:
            # 获取当前页面的工程名
            current_index = self.tab_widget.currentIndex()
            self.tmpProjectName = self.tab_widget.tabText(current_index)
            # 从缓存中清除模型数据
            delSpiFlashUpdateModelDict(self.tab_widget.tabText(current_index))
            # 删除当前页面
            self.tab_widget.removeTab(current_index)
            # 重新打开工程，并跳转页面
            # 界面导入
            self.addProject(self.tmpProjectName)
            # 设置当前选中的 Tab 为新增的 Tab
            tab_count = self.tab_widget.count() - 1
            self.tab_widget.setCurrentIndex(tab_count)
            # 提示结束
            self.show_message(getCNfromDict('TabBar05-btnmodifysucc'))
            addLog('TabBar02', 'info', f"modify over")
        else:
            self.show_message(getCNfromDict('TabBar05-btnmodifyerr'))
            addLog('TabBar02', 'error', f"modify error")

    def btn_generate_clicked(self):
        addLog('TabBar02', 'info', f"btn_generate_clicked")
        # 获取当前页面的工程名
        current_index = self.tab_widget.currentIndex()
        if current_index != -1:
            self.tmpProjectName = self.tab_widget.tabText(current_index)
            # 创建解压线程
            self.zip_thread = ZipThread_spiFlashUpdate(self.tmpProjectName)
            # 创建进度弹窗
            self.progress_dialog = ProgressDialog(getCNfromDict('TabBar02-btngenerating'), self)
            self.progress_dialog.show()

            # 连接信号和槽
            self.zip_thread.progress_signal.connect(self.progress_dialog.update_progress)
            self.zip_thread.status_signal.connect(self.btngenerate_status)
            self.zip_thread.status_signal.connect(self.progress_dialog.update_status)

            # 启动线程
            self.zip_thread.start()
            addLog('TabBar02', 'info', f"start generate")

    def btngenerate_status(self, status):
        """
        生成状态信息。
        """
        if status == 0:
            # 压缩完毕
            os.startfile(os.path.abspath('./generate/mcu'))
            self.show_message(getCNfromDict('TabBar02-btngeneratesucc'), 0)
            addLog('TabBar02', 'info', f"generate over")
        else:
            self.show_message(getCNfromDict('TabBar02-btnnewerr'), 1)
            addLog('TabBar02', 'error', f"generate error")

    def addProject(self, projectName: str):
        addLog('TabBar02', 'info', f"addProject {projectName}")

        # 复制模型文件
        if not os.path.exists("./project/mcu/"+projectName+"/SpiFlashUpdateModel.ini"):
            # 复制文件
            try:
                shutil.copy("./res/SpiFlashUpdateModel.ini", "./project/mcu/"+projectName+"/")
                addLog('TabBar02', 'info', f"addProject : copy model file finish!")
            except Exception as e:
                addLog('TabBar02', 'error', f"addProject : copy model file error!")
                return

        if addSpiFlashUpdateModelDict(projectName) != 0:
            addLog('TabBar02', 'error', f"addProject : model file unvaild!")
            return

        tab = QWidget()
        # 创建滚动区域
        scroll_area = QScrollArea(tab)
        scroll_area.setWidgetResizable(True)  # 允许滚动区域大小变化

        # 创建滚动区域内的容器
        container_widget = QWidget()
        scroll_area.setWidget(container_widget)

        # 创建容器的布局
        layout = QVBoxLayout(container_widget)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)

        # 添加任意数量的 QWidget 列表项
        SpiFlashUpdateModelList = getSpiFlashUpdateModelDict(projectName)
        # print(type(IflyModelList[0]))
        for SpiFlashUpdateModelUnit in SpiFlashUpdateModelList:
            if SpiFlashUpdateModelUnit['enable'] != '1':
                continue

            SpiFlashUpdateUnit = SpiFlashUpdateWidget(projectName, SpiFlashUpdateModelUnit, container_widget)
            SpiFlashUpdateUnit.setStyleSheet("border: 1px solid black;")
            layout.addWidget(SpiFlashUpdateUnit)

        # 将滚动区域添加到标签页的布局中
        tab_layout = QVBoxLayout(tab)
        tab_layout.addWidget(scroll_area)
        tab.setLayout(tab_layout)
        self.tab_widget.addTab(tab, projectName)
        addLog('TabBar02', 'info', f"addProject : over!")

    def scanProject(self):
        """
        扫描科大讯飞目录下的有效工程
        :return:
        """
        ensure_folder_exists("./project/mcu/")
        folders = get_all_folder_names("./project/mcu/")
        addLog('TabBar02', 'info', f"scan project: {folders}")
        for i in folders:
            # TODO::校验工程文件是否有效
            self.tmpProjectName = i
            self.addProject(self.tmpProjectName)

    def show_message(self, message, type=0):
        """显示提示消息框"""
        msg_box = QMessageBox()
        msg_box.setIcon(QMessageBox.Information)
        if type == 0:
            msg_box.setWindowTitle(getCNfromDict('megboxTitle-tip'))
        else:
            msg_box.setWindowTitle(getCNfromDict('megboxTitle-err'))
        msg_box.setText(message)
        msg_box.setStandardButtons(QMessageBox.Ok)
        msg_box.exec_()


